/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.repository.adaptor.method.setentityvalue;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import com.inspur.edp.cef.generator.repository.adaptor.AdapterGenUtils;
import com.inspur.edp.cef.generator.repository.dac.DataTypeDacGenContext;
import com.inspur.edp.cef.repository.assembler.DataTypeAssembler;
import com.inspur.edp.cef.repository.assembler.nesteddatatype.NestedDataColumnMapType;
import com.inspur.edp.cef.repository.assembler.nesteddatatype.NestedDataTypeAssembler;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfoCollection;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.BefDateSerUtil;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import org.eclipse.jdt.core.dom.*;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class NestedSetEntityValueGenerator extends SetEntityValueGenerator
{
	public NestedSetEntityValueGenerator(DataTypeDacGenContext dacContext, IGspCommonObject gspCommonObject, NestedDataTypeAssembler assembler, java.util.HashMap<String, String> mappingPropNames, DbColumnInfoCollection dbColumns)
	{
		super(dacContext,gspCommonObject, mappingPropNames, dbColumns);
	}


	@Override
	protected Block buildMethodBody()
{
	DataTypeAssembler tempVar = dacContext.getReposContext().getAssemblerInfo().getBaseAssembler().getAssemblerInstance();
	NestedDataTypeAssembler nestedAssembler = (NestedDataTypeAssembler)((tempVar instanceof NestedDataTypeAssembler) ? tempVar : null);
	if (nestedAssembler != null)
	{
		//多值ud存为一列情况需处理
		if (nestedAssembler.getColumnMapType() == NestedDataColumnMapType.SingleColumn)
		{
			return getSingleColumnUdtMethodBody(nestedAssembler);
		}
	}
	return super.buildMethodBody();
}

			//region 多值udt存为一列
	private static final String varObjectName = "obj";

	private Block getSingleColumnUdtMethodBody(NestedDataTypeAssembler assembler)
	{
		Block block = ast.newBlock();
		String entityTypeName = buildEntityTypeName();

//		ArrayList<Statement> statements = new ArrayList<Statement>();
		String mappingDicPropName = assembler.getColumnInfos().keySet().stream().findFirst().get();
		boolean isString = true;
		VariableDeclarationStatement readValueStatement = AdapterGenUtils
				.getReadValueStatement(ast, varObjectName, mappingDicPropName, RecordParamName, isString);
		block.statements().add(readValueStatement);

		Statement returnEmptyObjExpression = getIfNullStatement(entityTypeName);
		block.statements().add(returnEmptyObjExpression);

		Statement returnValueStatement = getReturnValueStatement(entityTypeName, varObjectName);
		block.statements().add(returnValueStatement);

		return block;
	}

	private Statement getIfNullStatement(String entityTypeName) {
		IfStatement ifStatement = ast.newIfStatement();
		InfixExpression expression = ast.newInfixExpression();
		expression.setLeftOperand(ast.newSimpleName(varObjectName));
		expression.setRightOperand(ast.newNullLiteral());
		expression.setOperator(InfixExpression.Operator.EQUALS);
		ifStatement.setExpression(expression);

		ifStatement.setThenStatement(getReturnEmptyObjExpression(entityTypeName));

		return ifStatement;
	}

	private Statement getReturnValueStatement(String entityTypeName,String valueName)
	{
//		try {
//			return new ObjectMapper().readValue((String)valueName, String.class);
//		} catch (IOException e) {
//			throw new RuntimeException(e);
//		}

		TryStatement tryStatement = ast.newTryStatement();

		Block tryBlock = ast.newBlock();
//		MethodInvocation deserializeInvocation = ast.newMethodInvocation();
//		ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
//		classInstanceCreation.setType(new TypeInfo(ObjectMapper.class).getType(ast, dacContext.getReposContext().getCefContext().getRootCompileUnitGenCtx()));
//		deserializeInvocation.setExpression(classInstanceCreation);
//		deserializeInvocation.setName(ast.newSimpleName("readValue"));
//		CastExpression castExpression = ast.newCastExpression();
//		castExpression.setExpression(ast.newSimpleName(varObjectName));
//		castExpression.setType(ast.newSimpleType(ast.newName("String")));
//		deserializeInvocation.arguments().add(castExpression);
//		TypeLiteral typeLiteral = ast.newTypeLiteral();
//		typeLiteral.setType(ast.newSimpleType(ast.newName(entityTypeName)));
//		deserializeInvocation.arguments().add(typeLiteral);
//		ReturnStatement returnStatement =ast.newReturnStatement();
//		returnStatement.setExpression(deserializeInvocation);
//		tryBlock.statements().add(returnStatement);
//		tryStatement.setBody(tryBlock);
		addGetMapperStatement(tryBlock);


		MethodInvocation methodInvocation=ast.newMethodInvocation();
		ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
		classInstanceCreation.setType(new TypeInfo(ObjectMapper.class).getType(ast,dacContext.getReposContext().getCefContext().getCefGenContext().getCoreGenContext()));
		methodInvocation.setExpression(classInstanceCreation);
		methodInvocation.setName(ast.newSimpleName("readValue"));

		MethodInvocation methodInvocation1=ast.newMethodInvocation();
		methodInvocation1.setName(ast.newSimpleName("getClobValue"));
		methodInvocation1.arguments().add(ast.newSimpleName("obj"));

		methodInvocation.arguments().add(methodInvocation1);

		TypeLiteral typeLiteral=ast.newTypeLiteral();
		typeLiteral.setType(ast.newSimpleType(ast.newName(entityTypeName)));

		methodInvocation.arguments().add(typeLiteral);
		ReturnStatement returnStatement=ast.newReturnStatement();
		returnStatement.setExpression(methodInvocation);
		tryBlock.statements().add(returnStatement);
		tryStatement.setBody(tryBlock);

		CatchClause catchClause = ast.newCatchClause();
		SingleVariableDeclaration singleVariableDeclaration=ast.newSingleVariableDeclaration();
		singleVariableDeclaration.setType(new TypeInfo(IOException.class).getType(ast, dacContext.getReposContext().getCefContext()));
		singleVariableDeclaration.setName(ast.newSimpleName("e"));
		catchClause.setException(singleVariableDeclaration);
		Block catchBodyBlock=ast.newBlock();
		addImport(CefException.class.getTypeName());
		ThrowStatement throwStatement= GeneratorUtil.getThrowStatementWithParamName(ast,"e");
//		ClassInstanceCreation rtExceptionInstanceCreation=ast.newClassInstanceCreation();
//		rtExceptionInstanceCreation.setType(new TypeInfo(RuntimeException.class).getType(ast));
//		rtExceptionInstanceCreation.arguments().add(ast.newSimpleName("e"));
//		throwStatement.setExpression(rtExceptionInstanceCreation);
		catchBodyBlock.statements().add(throwStatement);
		catchClause.setBody(catchBodyBlock);
		tryStatement.catchClauses().add(catchClause);

		return tryStatement;
	}

	private void addGetMapperStatement(Block tryBlock) {
		VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
		variableDeclarationFragment.setName(ast.newSimpleName("mapper"));
		setMappingNewInitializer(variableDeclarationFragment);

		VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
		variableDeclarationStatement.setType(ast.newSimpleType(ast.newSimpleName(ObjectMapper.class.getSimpleName())));
		addImport(ObjectMapper.class.getTypeName());
		tryBlock.statements().add(variableDeclarationStatement);
	}

	private void setMappingNewInitializer(VariableDeclarationFragment variableDeclarationFragment) {
		MethodInvocation methodInvocation=ast.newMethodInvocation();
		setNewMapperExpression(methodInvocation);
		methodInvocation.setName(ast.newSimpleName("getDeserializer"));
		setNewMapperArguments(methodInvocation);

		variableDeclarationFragment.setInitializer(methodInvocation);
	}

	private void setNewMapperExpression(MethodInvocation methodInvocation) {
		ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
		addImport(BefDateSerUtil.class.getTypeName());
		classInstanceCreation.setType(ast.newSimpleType(ast.newSimpleName(BefDateSerUtil.class.getSimpleName())));
		methodInvocation.setExpression(classInstanceCreation);
	}

	private void setNewMapperArguments(MethodInvocation methodInvocation) {
		TypeLiteral typeLiteral=ast.newTypeLiteral();
		typeLiteral.setType(ast.newSimpleType(ast.newSimpleName(buildEntityTypeName())));

		ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
		classInstanceCreation.setType(ast.newSimpleType(ast.newName(dacContext.getReposContext().getCefContext().getNameSpace()+".UdtDataDeserializer")));
		methodInvocation.arguments().add(typeLiteral);
		methodInvocation.arguments().add(classInstanceCreation);
	}

	private Statement getReturnEmptyObjExpression(String entityTypeName)
	{
		ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
		classInstanceCreation.setType(ast.newSimpleType(ast.newName(entityTypeName)));
		ReturnStatement returnStatement = ast.newReturnStatement();
		returnStatement.setExpression(classInstanceCreation);
		return returnStatement;
	}
		//endregion
}
